package com.wtwd.wtwddevice.service.impl;


import com.wtwd.device.constant.SeparatorConstant;
import com.wtwd.wtwddevice.service.IRedisService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author zdl
 * @Description
 * @create 2021-08-04 16:53
 */
@Service
public class RedisServiceImpl implements IRedisService {

    @Resource
    private RedisTemplate redisTemplate;




    @Override
    public void setKey(String key, String value, long expireTime, TimeUnit timeUnit) {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        if (expireTime < 1) {
            valueOperations.set(key, value);
        } else {
            valueOperations.set(key, value, expireTime, timeUnit);
        }
    }

    @Override
    public void setKey(String key, String value, long expireTime) {
        setKey(key, value, expireTime, TimeUnit.SECONDS);
    }

    @Override
    public void setHash(String key, Map<String, Object> map, long expireTime, TimeUnit timeUnit) {
        redisTemplate.opsForHash().putAll(key, map);
        if (expireTime > 0) {
            redisTemplate.expire(key, expireTime, timeUnit);
        }
    }

    @Override
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    @Override
    public String getValue(String key) {
        if (redisTemplate.hasKey(key)) {
            return String.valueOf(redisTemplate.opsForValue().get(key));
        }
        return null;
    }


    @Override
    public boolean deleteKey(String key) {
        return redisTemplate.delete(key);
    }



    @Override
    public boolean verifyCode(String account, int authType, String code) {
        if (StringUtils.isBlank(code)) {
            return false;
        }
        String value = getValue(account + SeparatorConstant.DELIMITER + authType);
        return code.equals(value);
    }

    @Override
    public boolean createCode(String account, int authType, String code, long expireTime) {
        setKey(account + SeparatorConstant.DELIMITER + authType, code, expireTime);
        return true;
    }

    @Override
    public boolean lock(String key, String value, long expireTime) {
        boolean locked = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
        return locked;
    }

    @Override
    public boolean unlock(String key, String value) {
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
            return false;
        }
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript();
        //用于解锁的lua脚本位置
        redisScript.setScriptText(
                "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                        "return redis.call('del', KEYS[1]) " +
                        "else " +
                        "return 0 " +
                        "end");
        redisScript.setResultType(Long.class);
        Object result = redisTemplate.execute(redisScript, Collections.singletonList(key), value);
        return result.equals(Long.valueOf(1));
    }

    @Override
    public String increment(String key, long initialValue, long expiredTime, long maxNumber) {
        BoundValueOperations boundValueOperations = redisTemplate.boundValueOps(key);
        Long increment = boundValueOperations.increment();
        if (increment == initialValue) {//为初值时,设置过期时间
            boundValueOperations.expire(expiredTime, TimeUnit.DAYS);
        }
        return String.valueOf(increment % maxNumber);
    }


    @Override
    public Map<String, Object> getHashValue(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    @Override
    public void saveCache(String key, String hashKey, Object object) {
        Map<String, Object> map = redisTemplate.opsForHash().entries(key);
        if (map == null) {
            map = new HashMap<String, Object>();
        }
        map.put(hashKey, object);
        redisTemplate.opsForHash().putAll(key, map);
    }



}
